﻿using System.Reflection;
namespace CommandLinex
{
    public class CommandLineParser
    {
        /// <summary>
        /// 解析命令行参数到指定类型的对象
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="args">命令行参数数组</param>
        /// <returns>解析后的对象</returns>
        public T Parse<T>(string[] args) where T : new()
        {
            var result = new T();
            var properties = typeof(T).GetProperties();
            var argsDict = ParseArgumentsToDictionary(args);

            foreach (var property in properties)
            {
                var optionAttribute = property.GetCustomAttribute<ArgumentAttribute>();
                if (optionAttribute == null) continue;

                if (argsDict.TryGetValue(optionAttribute.Name, out var value))
                {
                    // 如果找到参数值，进行处理
                    var processedValue = ProcessValue(value, optionAttribute.ProcessorType, property.PropertyType, optionAttribute.Name);
                    property.SetValue(result, processedValue);
                }
                else if (optionAttribute.IsRequired)
                {
                    // 必选参数未提供
                    throw new ArgumentException($"参数 --{optionAttribute.Name} 为空，请设置...{optionAttribute.Description}");
                }
                else if (optionAttribute.DefaultValue != null)
                {
                    // 使用默认值
                    property.SetValue(result, optionAttribute.DefaultValue);
                }
            }

            return result;
        }

        /// <summary>
        /// 生成帮助信息
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <returns>帮助文本</returns>
        public string GetHelpText<T>()
        {
            var lines = new List<string>();
            var properties = typeof(T).GetProperties();

            lines.Add("Usage:");
            lines.Add("  --<option> <value>");
            lines.Add("");
            lines.Add("Options:");

            foreach (var property in properties)
            {
                var optionAttribute = property.GetCustomAttribute<ArgumentAttribute>();
                if (optionAttribute == null) continue;

                var line = $"  --{optionAttribute.Name}";
                if (!optionAttribute.IsRequired && optionAttribute.DefaultValue != null)
                {
                    line += $" (default: {optionAttribute.DefaultValue})";
                }
                line += $"  {optionAttribute.Description}";

                lines.Add(line);
            }

            return string.Join(Environment.NewLine, lines);
        }

        private Dictionary<string, string> ParseArgumentsToDictionary(string[] args)
        {
            var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i].StartsWith("--"))
                {
                    var key = args[i].Substring(2);
                    if (i + 1 < args.Length && !args[i + 1].StartsWith("--"))
                    {
                        dict[key] = args[i + 1];
                        i++; // 跳过下一个参数，因为它已经是值了
                    }
                    else
                    {
                        dict[key] = null; // 没有值的参数
                    }
                }
            }

            return dict;
        }

        private object ProcessValue(string value, Type processorType, Type targetType, string fieldName)
        {
            if (processorType != null)
            {
                // 使用自定义处理器
                var processor = Activator.CreateInstance(processorType) as ICommandLineValueProcessor;
                if (processor == null)
                {
                    throw new InvalidOperationException($"Processor type {processorType} does not implement ICommandLineValueProcessor.");
                }

                return processor.Process(value, targetType);
            }

            // 没有处理器，尝试直接转换
            if (targetType == typeof(string))
            {
                return value;
            }
            if (targetType == typeof(Boolean))
            {
                return bool.Parse(value);
            }
            if (targetType.IsEnum)
            {
                return Enum.Parse(targetType, value, true);
            }

            return Convert.ChangeType(value, targetType);
        }
    }
}